package demo.Design.principle;

/**
 * @Auther: hjy(lc))
 * @Date: 2022/10/12-10-12-17:01
 * @Description：demo.Design.principle    八大设计原则
 */
/*
单一职责原则
    用于控制类的粒度大小
    一个对象应该只包含单一的职责，并且该职责被完整的封装在一个类中
        // 程序员
    class Coder{
        // 编程
        public void coding(){
        }
    }
    // 工人
    class Worker{
        // 打螺丝
        public void work(){
        }
    }
    // 骑手
    class Rider {
        // 送外卖
        public void ride(){
        }
    }
 */
/*
    开闭原则
        软件实体应当对扩展开放，对修改关闭
            // 程序员
    public abstract class Coder {
        public abstract void coding();
        // Java程序员
        class JavaCoder extends Coder{
            @Override
            public void coding() {
            }
        }
        // Python程序员
        class PythonCoder extends Coder{
            @Override
            public void coding() {
            }
        }
        // PHP程序员
        class PHPCoder extends Coder{
            @Override
            public void coding() {
            }
        }
    }
*/
/*
    里氏替换原则
        对子类型的特别定义  所有引用基类的地方必须能透明的使用其子类对象
        子类可以扩展父类的功能，但不能改变父类原有的功能：
        子类可以实现父类的抽象方法，但不能覆盖父类的非抽象方法。
        子类可以增加自己特有的方法。
        子类的方法重载父类的方法时，方法的前置条件（方法的输入/入参）要比父类方法的输入参数更宽松。
        子类的方法实现父类的方法时（重写/重载/实现抽象方法），方法的后置条件（方法的输出/返回值）要比父类更严格或与父类一样。
            // 程序员
    public abstract class Coder {
        // 写代码
        public void coding() {
        }
        // Java程序员
        class JavaCoder extends Coder{
            // 打游戏
            public void game(){
            }
        }
    }

    ！！！ 里氏替换也是实现开闭原则的重要方式
 */
/*
    依赖倒转原则
        高层模块不应依赖于底层模块，它们都应该依赖抽象。抽象不应依赖于细节，细节应该依赖于抽象
            public class Main {
        public static void main(String[] args) {
            UserController controller = new UserController();
        }
        interface UserMapper {
            // 接口中只做 CRUD 方法定义
        }
        static class UserMapperImpl implements UserMapper {
            // 实现类完成 CRUD 具体实现
        }
        interface UserService {
            // 业务接口定义......
        }
        static class UserServiceImpl implements UserService {
            // 现在由Spring来为我们选择一个指定的实现类，然后注入，而不是由我们在类中硬编码进行指定
            @Resource
            UserMapper mapper;
            // 业务代码实现......
        }
        static class UserController {
            // 直接使用接口，就算你改实现，我也不需要再修改代码了
            @Resource
            UserService service;
            // 业务代码......
        }
    }

    通过使用接口，将原有的强关联给弱化，只需要知道接口中定义了什么方法然后去使用即可。而具体的操作由接口的实现类来完成，并由 Spring 来为我们注入，而不是我们通过硬编码的方式去指定。
*/
/*
    接口隔离原则     对接口的细化 客户端不应该依赖于那些它不需要的接口

*/
/*
    合成复用原则    委派 优先使用对象组合，而不是通过继承来达到复用的目的
    在一个新的对象里面使用一些已有的对象，使之成为新对象的一部分，新的对象通过向这些对象的委派达到复用已有功能的目的。在考虑将某个类通过继承关系在子类得到父类已经实现的方法时，应该先考虑使用合成的方式来实现复用。
    class A {
        public void connectDatabase(){
            System.out.println("我是连接数据库操作！");
        }
    }
    // 直接通过继承的方式，得到 A 的数据库连接逻辑
    class B extends A{
        public void test(){
            System.out.println("我是B的方法，我也需要连接数据库！");
            // 直接调用父类方法
            connectDatabase();
        }
    }
    通过继承的方式实现复用，是将类 B 直接指定继承自类 A 的。如果有一天，由于业务的更改，数据库连接操作不再由A来负责，而是由C去负责。就不得不将需要复用 A 中方法的子类全部进行修改，这样是费时费力的。并且还有一个问题，通过继承子类会得到一些父类中的实现细节，比如某些字段或是方法，这样直接暴露给子类，并不安全。
    -----------------------------》
        class A {
        public void connectDatabase(){
            System.out.println("我是连接数据库操作！");
        }
    }
    // 不进行继承，而是在用的时候给我一个 A，当然也可以抽象成一个接口，更加灵活
    class B {
        public void test(A a){
            System.out.println("我是B的方法，我也需要连接数据库！");
            // 通过对象 A 去执行
            a.connectDatabase();
        }
    }
*/
/*
    迪米特原则（最少知识原则）  是对程序内部数据交互的限制。
    一个类/模块对其他的类/模块有越少的交互越好。当一个类发生改动，与其相关的类需要尽可能少的受影响。这样我们在维护项目的时候会更加轻松一些。其实本质还是降低耦合度。
        public class Main {
        public static void main(String[] args) throws IOException {
            // 假设我们当前的程序需要进行网络通信
            Socket socket = new Socket("localhost", 8080);
            Test test = new Test();
            // 现在需要执行 test 方法来做一些事情
            test.test(socket);
        }
        static class Test {
            // 比如 test 方法需要得到我们当前 Socket 连接的本地地址
            public void test(Socket socket){
                System.out.println("IP地址：" + socket.getLocalAddress());
            }
        }
    }
    虽然这种写法没有问题，直接提供一个 Socket 对象供使用，然后再由 test 方法来取出 IP 地址。但是这样显然违背了迪米特法则，实际上这里的 test 方法只需要一个 IP 地址即可。完全可以只传入一个字符串，而不是整个 Socket 对象，这样就保证了与其他类的交互尽可能的少。要是某一天，Socket 类中的这些方法发生修改了，那我们就得连带着去修改这些类，很麻烦。
    就像在餐厅吃完了饭，应该是自己扫码付款，而不是直接把手机交给老板来帮你操作付款。
    --------------------------》
        public class Main {
        public static void main(String[] args) throws IOException {
            Socket socket = new Socket("localhost", 8080);
            Test test = new Test();
            // 在外面解析好再传入
            test.test(socket.getLocalAddress().getHostAddress());
        }
        static class Test {
            // 一个字符串就搞定了
            public void test(String str){
                System.out.println("IP地址："+str);
            }
        }
    }

*/
public class SRP {

}
